/**
 * Copyright (c) 2011 Tomi Paananen.
 *
 * Part of Quick Gestures engine library.
 */

// Own header
#include "gesturemodel.h"

// qgengine includes
#include "gesture.h"
#include "qgtrace.h"


/*!
  \class GestureModel
  \brief A model containing a set of gestures.
*/


/*!
  Constructor.
*/
GestureModel::GestureModel(QObject *parent /* = 0 */)
    : QAbstractListModel(parent)
{
    QHash<int, QByteArray> roles;
    roles[IdRole] = "id";
    roles[NameRole] = "name";
    roles[AttributesRole] = "attributes";
    roles[PointsRole] = "points";
    roles[GestureObject] = "gestureObject";
    roles[GesturePointer] = "gesturePointer";
    setRoleNames(roles);
}


/*!
  Copy constructor.
  Warning: Do not use!!! The only reason this here is to enable the class to be
  declared as a meta type.
*/
GestureModel::GestureModel(const GestureModel &gestureModel,
                           QObject *parent /* = 0*/)
    : QAbstractListModel(parent)
{
    Q_UNUSED(gestureModel);
}


/*!
  Destructor.
*/
GestureModel::~GestureModel()
{
    // Delete all the gestures.
    clear();
}


/*!
  From QAbstractListModel.
*/
QVariant GestureModel::data(const QModelIndex &index,
                            int role /* = Qt::DisplayRole */) const
{
    const int itemIndex(index.row());

    if (!index.isValid() || itemIndex >= m_gestures.count()) {
        // Invalid index!
        DEBUG_INFO("Invalid index:" << itemIndex);
        return QVariant();
    }

    QVariant value = QVariant();
    Gesture *gesture(m_gestures[itemIndex]);

    switch (role) {
    case IdRole:
        value = QVariant::fromValue(gesture->id());
        break;
    case NameRole:
        value = QVariant::fromValue(gesture->name());
        break;
    case AttributesRole:
        value = QVariant::fromValue(gesture->attributes());
        break;
    case PointsRole:
        value = QVariant::fromValue(gesture->modifiablePoints());
        break;
    case GestureObject:
        value = QVariant::fromValue(*gesture);
        break;
    case GesturePointer:
        value = QVariant(QMetaType::QObjectStar, gesture);
        break;
    } // switch (role)

    return value;
}


/*!
  From QAbstractListModel.
*/
int GestureModel::rowCount(const QModelIndex &parent /* = QModelIndex() */) const
{
    Q_UNUSED(parent);
    return m_gestures.count();
}


/*!
  From QAbstractListModel.
*/
void GestureModel::removeRow(int row, const QModelIndex &parent)
{
    if (row < 0 || row >= m_gestures.count()) {
        // Invalid row!
        return;
    }

    beginRemoveRows(parent, row, row);
    delete m_gestures.takeAt(row);
    endRemoveRows();
}


/*!
  Returns the gestures contained by the model.
*/
QList<Gesture*> GestureModel::gestures() const
{
    return m_gestures;
}


/*!
  Returns a gesture with \a index or NULL if not found.
*/
Gesture *GestureModel::gestureByIndex(int index) const
{
    if (index < 0 || index >= m_gestures.count()) {
        DEBUG_INFO("Invalid index!");
        return 0;
    }

    return m_gestures[index];
}


/*!
  Finds and returns a gesture with \a id. Returns a pointer to the found
  gesture or NULL if not found.
*/
Gesture *GestureModel::gestureById(quint32 id) const
{
    const int count(m_gestures.count());

    if (!count) {
        DEBUG_INFO("Warning: No gestures set!");
        return NULL;
    }

    for (int i = 0; i < count; ++i) {
        if (m_gestures[i] && m_gestures[i]->id() == id) {
            // Found the gesture!
            return m_gestures[i];
        }
    }

    //DEBUG_INFO("Failed to find a gesture with ID:" << id);
    return 0;
}


/*!
  Finds and returns a gesture with \a name. Returns a pointer to the found
  gesture or NULL if not found.
*/
Gesture *GestureModel::gestureByName(const QString &name) const
{
    const int count(m_gestures.count());

    for (int i = 0; i < count; ++i) {
        if (m_gestures[i] && !m_gestures[i]->name().compare(name)) {
            // Found the gesture!
            return m_gestures[i];
        }
    }

    DEBUG_INFO("Failed to find a gesture with name:" << name);
    return 0;
}


/*!
  Returns the gesture count. For convenience.
*/
int GestureModel::count() const
{
    return rowCount();
}


/*!
  Adds \a gesture into the model. Returns true if successful, false otherwise.
*/
bool GestureModel::addGesture(Gesture *gesture)
{
    if (!gesture || m_gestures.contains(gesture)) {
        // The given gesture is invalid or the model already contains the
        // gesture. Note that if the model already contains a gesture with the
        // same ID, it will be replaced by the given gesture.
        DEBUG_INFO("Failed to add gesture into the model!");
        return false;
    }

    appendGesture(gesture);
    return true;
}


/*!
  Sets \a gestures as the model content.
*/
void GestureModel::setGestures(QList<Gesture*> &gestures)
{
    DEBUG_POINT;
    clear();
    beginInsertRows(QModelIndex(), 0, gestures.count() - 1);
    m_gestures = gestures;
    endInsertRows();
}


/*!
  Removes a gesture with \a id from the model. Returns true if successful,
  false otherwise e.g. in case no gesture with the given ID is found.
*/
bool GestureModel::removeGesture(quint32 id)
{
    DEBUG_INFO(id);
    const int count(m_gestures.count());

    for (int i = 0; i < count; ++i) {
        if (m_gestures[i] && m_gestures[i]->id() == id) {
            // Found the gesture! Remove it from the model and delete it.
            beginRemoveRows(QModelIndex(), i, i);
            delete m_gestures.takeAt(i);
            endRemoveRows();
            emit countChanged(count - 1);
            return true;
        }
    }

    // Not found!
    DEBUG_INFO("Failed to find a gesture with ID" << id << "!");
    return false;
}


/*!
  Deletes all model content.
*/
void GestureModel::clear()
{
    DEBUG_INFO("Will delete" << rowCount() << "gestures.");

    while (rowCount()) {
        removeRow(0, QModelIndex());
    }

    emit countChanged(0);
}


/*!
  Informs (e.g. user interface) about an update of the gesture with \a index.
  Returns true if successful i.e. a gesture with the given index exists,
  false otherwise.
*/
bool GestureModel::updateGestureByIndex(int index)
{
    //DEBUG_INFO(index);

    if (index >= 0 && index < m_gestures.count()) {
        // Valid index!
        QModelIndex modelIndex = createIndex(index, 0, 0);
        emit dataChanged(modelIndex, modelIndex);
        return true;
    }

    DEBUG_INFO("Invalid index!");
    return false;
}


/*!
  Returns the point with index \a index of a gesture with ID \a gestureId.
*/
QPoint GestureModel::pointAt(quint32 gestureId, int index) const
{
    Gesture *gesture = gestureById(gestureId);

    if (gesture) {
        if (index >= 0 && index < gesture->points().count()) {
            return gesture->points()[index];
        }
    }
    else {
        DEBUG_INFO("Failed to find a gesture with ID" << gestureId << "!");
    }

    DEBUG_INFO("Failed to find a point with index" << index <<
               "of gesture with ID" << gestureId << "!");
    return QPoint();
}


/*!
  Adds \a gesture into the model. If the model already contains a gesture with
  the same ID as the given gesture, the old gesture will be replaced by the
  new one.
*/
void GestureModel::appendGesture(Gesture *gesture)
{
    if (!gesture) {
        // This should not be possible, but better safe than sorry.
        return;
    }

    Gesture *oldGesture = gestureById(gesture->id());
    const int count(m_gestures.count());

    if (oldGesture) {
        DEBUG_INFO("Replacing a gesture with ID" << gesture->id());
        *oldGesture = *gesture;

        // Notify the UI.
        for (int i = 0; i < count; ++i) {
            if (m_gestures[i]->id() == gesture->id()) {
                updateGestureByIndex(i);
                break;
            }
        }
    }
    else {
        DEBUG_INFO("Appending a gesture with ID" << gesture->id());
        beginInsertRows(QModelIndex(), count, count);
        m_gestures.append(gesture);
        endInsertRows();
        emit countChanged(count + 1);
    }
}


// End of file.
